#include <string.h>
#include <memory.h>
#include <stdlib.h>
#include <stdio.h>

#include "zr5.h"
#include "sha3/sph_blake.h"
#include "sha3/sph_groestl.h"
#include "sha3/sph_jh.h"
#include "sha3/sph_keccak.h"
#include "sha3/sph_skein.h"

enum {KECCAK_ID = 0, BLAKE_ID, GROESTL_ID, JH_ID, SKEIN_ID};  // need this one zero based

// function prototypes
short test_zr5_hash_512(unsigned * passedTestsPtr, unsigned * failedTestsPtr);
short test_zr5(unsigned * passedTestsPtr, unsigned * failedTestsPtr);
short test_single_hashes(unsigned * passedTestsPtr, unsigned * failedTestsPtr);
short test_single_hash(uint8_t* input, unsigned len, uint8_t* expected, uint8_t algoIndex, unsigned * passedTestsPtr, unsigned * failedTestsPtr);

// g++ zr5test.cpp zr5.c -o testzr5
int main(int argc, char* argv[])
{
	unsigned		total_passed = 0;
	unsigned		total_failed = 0;
	unsigned int	i;
	uint8_t		zr5_out_512[64];	// results for testing zr5_hash_512
	uint8_t		zr5_out_256[32];		// results for testing zr5_hash

	// we don't have full test results for test0
	// char		test0[] = "\x01\x00\x00\x00\x4e\x42\xb7\x59\xbd\x65\x68\x59\x9c\xff\x71\x4b\x67\x9d\xbf\x94\x6543c9ba\x8444f7b8\xb964bf21\x71070000\xc6bb8526\xc7e59d3b\xc92afd77\xb11e544a\xf69ae0d4\xda4f98bc\x6e981f3d\xbb20f185\xa918e654\xffff0b1e\x00000000";

	// test1 three byte test
	// This test is too short; Proof of Knowledge requires more bytes
	// uint8_t 		test1[] = "\x00\x11\x22";
	//uint8_t		empty[] = "\x00\x00\x00\x00\x00\x00\x00\x00";
	//uint8_t 	  xpec_k1[] = "\x94\x77\x84\xf1\x39\x86\x9e\xac\xae\xff\x6b\xd6\x72\x97\xa4\xfb\xb6\xec\x56\x2a\x50\xfa\x17\x4f\x95\x2c\x75\x9b\x2e\x1a\xcf\x73\xf6\xf8\x0a\x0f\x6e\x24\x12\x73\x9a\x80\xdc\xe0\x41\x45\xc5\xb4\x5b\x72\xb1\xb7\xb1\xd2\x25\x97\x23\xaa\xa7\x04\xfa\xae\x5b\xe6";
	//uint8_t 	xpec1_512[] = "\xf5\x2f\x44\x4f\x7e\xe6\xa5\x0b\x19\x7c\xc9\xf0\x3e\xd0\x2d\xbe\xec\x3d\xe9\x10\xd1\x84\xb1\xd2\x03\xc7\xf1\xe0\x45\x4e\xd1\xb3\x28\x0a\xab\x39\xdc\x67\xa6\xff\xdb\xdb\x42\x8c\x48\xce\xa4\xae\x5e\xa5\x60\x15\x4c\x8a\xd0\x16\xdd\xf3\x8d\x2e\x7c\x49\xfc\x2e";
	//uint8_t 		xpec1[] = "\x28\x0a\xab\x39\xdc\x67\xa6\xff\xdb\xdb\x42\x8c\x48\xce\xa4\xae\x5e\xa5\x60\x15\x4c\x8a\xd0\x16\xdd\xf3\x8d\x2e\x7c\x49\xfc\x2e";

	// 65 byte test
	uint8_t		test2[] = "\x04\xfc\x97\x02\x84\x78\x40\xaa\xf1\x95\xde\x84\x42\xeb\xec\xed\xf5\xb0\x95\xcd\xbb\x9b\xc7\x16\xbd\xa9\x11\x09\x71\xb2\x8a\x49\xe0\xea\xd8\x56\x4f\xf0\xdb\x22\x20\x9e\x03\x74\x78\x2c\x09\x3b\xb8\x99\x69\x2d\x52\x4e\x9d\x6a\x69\x56\xe7\xc5\xec\xbc\xd6\x82\x84";
	uint8_t	  xpec_k2[] = "\x62\xf8\xd0\xca\x61\xeb\xbe\xef\x22\x31\x37\xf5\x71\xd6\x5c\xf7\x0f\x1a\x89\xce\x44\x07\x46\x83\x02\x3e\x25\x8c\xa8\x48\xb5\x23\xb7\x18\x39\x67\x15\x61\xf3\x5e\x5a\x26\x50\xb0\x03\x8e\xf6\xfb\x90\x7b\xc7\xb3\x81\x2c\x34\x42\x3b\x3b\xd6\x77\xb0\x22\xa3\x39";
	uint8_t	xpec2_512[] = "\xa7\x9c\xeb\x61\x08\xa9\xe3\xf0\xcf\x4a\xd6\xd0\x50\x46\x19\x76\xaa\xae\xb1\xa4\xa8\x5b\xcb\xb3\x84\x26\x46\xf9\x9d\xf7\xf6\xc3\x85\xff\xc1\xbf\x48\x08\x41\xe3\x65\x70\xd6\x9f\xd8\x5f\xff\xe5\xd9\x21\x66\x6c\xad\x28\x8b\x70\xc9\x4a\x40\xe2\xd4\xa2\xc9\x28";
	uint8_t xpec2_256[] = "\x85\xff\xc1\xbf\x48\x08\x41\xe3\x65\x70\xd6\x9f\xd8\x5f\xff\xe5\xd9\x21\x66\x6c\xad\x28\x8b\x70\xc9\x4a\x40\xe2\xd4\xa2\xc9\x28";

	// 80 byte test
	uint8_t		test3[] = "\x01\x80\x64\x86\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x2a\xb0\x32\x51\x87\xd4\xf2\x8b\x6e\x22\xf0\x86\x48\x45\xdd\xd5\x0a\xc4\xe6\xaa\x22\xa1\x70\x9f\xfb\x42\x75\xd9\x25\xf2\x66\x36\x30\x0e\xed\x54\xff\xff\x0f\x1e\x2a\x9e\x23\x00";
	uint8_t	  xpec_k3[] = "\0x51\xb4\x30\x9f\x78\x9f\xba\xa7\xe5\xf0\x40\x2b\x70\x07\x2a\x60\xe8\xa7\x05\xb1\x95\x92\x38\x6b\xd1\x36\x37\x79\x93\x5c\x45\xf0\x11\xe1\x33\x63\x49\x18\x20\x95\x03\x92\x50\x2a\x9d\x3c\x1f\x76\x45\x1c\x37\x9f\x9d\x98\x3c\x98\x86\x43\x22\xf2\xec\xb9\x5f\x84";
	uint8_t	xpec3_512[] = "\xee\x0c\x3d\x3b\xe3\xdc\x49\xed\x47\xa6\x0b\xda\x98\x76\x1e\xc6\x01\x2b\x8c\x3f\x54\xc5\x86\xd1\x00\x9f\xe5\x96\xef\xc5\x4c\x35\x00\x00\x03\x58\x88\xfe\xa2\xf9\x6e\x3e\xf9\x96\xbe\xda\x4f\xa4\xc4\xc4\xd0\x3b\x37\x11\x84\xd1\xf5\x75\xf9\xd1\x44\xb7\xa1\x64";
	uint8_t	xpec3_256[] = "\x00\x00\x03\x58\x88\xfe\xa2\xf9\x6e\x3e\xf9\x96\xbe\xda\x4f\xa4\xc4\xc4\xd0\x3b\x37\x11\x84\xd1\xf5\x75\xf9\xd1\x44\xb7\xa1\x64";
	uint8_t	xr5_out[64];

	// another 80 byte test from the second examples
	uint8_t		   test4[] = "\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x2a\xb0\x32\x51\x87\xd4\xf2\x8b\x6e\x22\xf0\x86\x48\x45\xdd\xd5\x0a\xc4\xe6\xaa\x22\xa1\x70\x9f\xfb\x42\x75\xd9\x25\xf2\x66\x36\x30\x0e\xed\x54\xff\xff\x0f\x1e\xa4\x0d\x12\x00";
	uint8_t		 xpec_k4[] = "\x4b\xcf\x8f\x62\x57\x19\x23\x4e\xf2\xf9\x6e\xd5\x5d\x6d\xa3\x55\xbb\xbc\xc9\xb9\x95\x95\xa2\x80\xff\x9a\x85\x61\xbe\x3d\x70\x42\xe5\xe8\x8c\x0c\x59\x4d\x6e\x3c\x8e\x41\x53\xb9\x81\xe0\x1c\x60\x8d\xbe\xd2\xc5\x7b\xc3\xb8\x89\x42\xe0\xa5\x9b\xcd\x06\x9a\x07";
	uint8_t		  skein4[] = "\xca\xa3\x29\x81\x05\x20\x7e\x16\xcf\x3b\xd4\x64\x48\x3b\x73\xad\x42\x7b\x2f\x55\xa2\x23\x0a\xdc\x91\x47\xe7\x90\x02\x72\xfe\xed\xf6\x16\xbd\xfa\x45\xbd\xaf\xc2\x04\xa2\x60\x35\x4b\x6d\xd8\x1e\x0a\x9f\xf5\xd5\xe1\x78\x9e\x91\x37\xba\x77\xc3\x3e\xd2\x51\xb3";
	uint8_t		  blake4[] = "\x8b\x27\xab\xbe\x2e\x77\x0d\x4c\x90\xba\xa7\x0b\x11\xd5\xe9\xc2\x65\x06\x9a\x3f\x19\xbc\x67\x42\x31\xc5\x31\x0a\x95\x6b\x55\xd1\x2f\xd8\x78\x57\x49\x2a\x69\xab\xf1\x73\xab\xd8\xac\x25\xbc\x31\x4c\x9e\x2e\x92\x31\x58\xd9\xbe\xfc\x00\x5a\x9c\x86\x52\xfa\x58";
	uint8_t			 jh4[] = "\xb4\xa6\xf5\x85\x88\x35\x94\xcc\xfd\xa4\x8a\x75\x1c\x7d\x88\xd6\x32\x1e\x8e\x20\x23\xa0\x60\xfd\x67\xae\x70\x09\x28\x2b\x92\xb1\xf9\x97\x6f\x4e\x93\xd4\x53\xfa\xcb\xb8\x1a\x42\x19\x15\x8b\x77\x59\xab\xe1\xde\xdb\x47\x34\xb4\x8a\x73\xa6\xd6\x0f\x2c\x64\xbf";
	uint8_t		groestl4[] = "\x98\xe4\xdc\x02\x81\xfa\x2c\xdf\x48\xe6\x16\x47\x5a\x42\x0d\xae\x42\x5c\x99\x46\x76\x30\xb0\xc4\xed\xb3\xae\x6e\xaf\xeb\xa8\x17\x1d\x28\x43\xfe\xa9\x19\xbb\x16\x9f\xd3\xc7\x63\x69\xdb\x10\xfd\xc9\x90\xea\x83\x22\x8d\xae\x51\xe2\x10\x35\xb4\xc1\x22\xd7\x65";
	uint8_t	   xpec4_512[] = "\xa9\x08\x52\x54\x52\x9e\xa2\x88\xf1\x65\x2a\x08\x43\xa3\xd9\xeb\x74\x63\x17\x55\x49\xc9\x31\xd3\xc3\x2d\x43\x1b\x6c\x03\x00\x00\xe6\xb8\xeb\xfb\x6f\x2a\x39\x2e\xe4\x99\x3d\x9d\xd1\xd5\x83\x23\x24\x9e\xa5\x49\xf5\xfe\x21\xc5\xf4\xad\x2d\x28\x64\x38\x87\xdc";
	uint8_t		   zr5_4[] = "\xa9\x08\x52\x54\x52\x9e\xa2\x88\xf1\x65\x2a\x08\x43\xa3\xd9\xeb\x74\x63\x17\x55\x49\xc9\x31\xd3\xc3\x2d\x43\x1b\x6c\x03\x00\x00";

	// last 80 byte test from the second examples
	uint8_t		   test5[] = "";
	uint8_t		 xpec_k5[] = "";
	uint8_t		  skein5[] = "";
	uint8_t		  blake5[] = "";
	uint8_t			 jh5[] = "";
	uint8_t		groestl5[] = "";
	uint8_t		   zr5_5[] = "";

	#ifdef TEST_VERBOSELY
	printf("zr5_hash_512 test4 input: ");
	for(i=0; i< 3; i++) { printf("%02x", test4[i]); }
	printf("\n");
	printf("%12s", "ExpectedK: ");
	for(i=0; i< 64; i++) { printf("%02x", xpec_k4[i]); }
	printf("\n");
	#endif // TEST_VERBOSELY

	uint32_t gls32 = getleastsig32((uint8_t *)&xpec_k4[0], 0);
	#ifdef TEST_VERBOSELY
	printf("Expected getleastsig32: %u   (0x", gls32);
	for(i=0; i< sizeof(uint32_t); i++)  { printf("%02x", *( (uint8_t *)(&gls32) + i) ); }
	printf(")\n");
	#endif // TEST_VERBOSELY

	test_single_hashes(&total_passed, &total_failed);
	test_zr5_hash_512(&total_passed, &total_failed);
	test_zr5(&total_passed, &total_failed);

	printf("%u ZR5 tests total.\n", total_passed + total_failed);
	printf("%u tests passed.\n", total_passed);
	printf("%u tests failed.\n", total_failed);

	return 0;
}


short test_single_hashes(unsigned * passedTestsPtr, unsigned * failedTestsPtr)
{
	// another 80 byte test from the second examples
	uint8_t		   kin1[] = "\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x2a\xb0\x32\x51\x87\xd4\xf2\x8b\x6e\x22\xf0\x86\x48\x45\xdd\xd5\x0a\xc4\xe6\xaa\x22\xa1\x70\x9f\xfb\x42\x75\xd9\x25\xf2\x66\x36\x30\x0e\xed\x54\xff\xff\x0f\x1e\xa4\x0d\x12\x00";
	uint8_t		 keccak_out1[] = "\x4b\xcf\x8f\x62\x57\x19\x23\x4e\xf2\xf9\x6e\xd5\x5d\x6d\xa3\x55\xbb\xbc\xc9\xb9\x95\x95\xa2\x80\xff\x9a\x85\x61\xbe\x3d\x70\x42\xe5\xe8\x8c\x0c\x59\x4d\x6e\x3c\x8e\x41\x53\xb9\x81\xe0\x1c\x60\x8d\xbe\xd2\xc5\x7b\xc3\xb8\x89\x42\xe0\xa5\x9b\xcd\x06\x9a\x07";
	uint8_t		  skein_out1[] = "\xca\xa3\x29\x81\x05\x20\x7e\x16\xcf\x3b\xd4\x64\x48\x3b\x73\xad\x42\x7b\x2f\x55\xa2\x23\x0a\xdc\x91\x47\xe7\x90\x02\x72\xfe\xed\xf6\x16\xbd\xfa\x45\xbd\xaf\xc2\x04\xa2\x60\x35\x4b\x6d\xd8\x1e\x0a\x9f\xf5\xd5\xe1\x78\x9e\x91\x37\xba\x77\xc3\x3e\xd2\x51\xb3";
	uint8_t		  blake_out1[] = "\x8b\x27\xab\xbe\x2e\x77\x0d\x4c\x90\xba\xa7\x0b\x11\xd5\xe9\xc2\x65\x06\x9a\x3f\x19\xbc\x67\x42\x31\xc5\x31\x0a\x95\x6b\x55\xd1\x2f\xd8\x78\x57\x49\x2a\x69\xab\xf1\x73\xab\xd8\xac\x25\xbc\x31\x4c\x9e\x2e\x92\x31\x58\xd9\xbe\xfc\x00\x5a\x9c\x86\x52\xfa\x58";
	uint8_t			 jh_out1[] = "\xb4\xa6\xf5\x85\x88\x35\x94\xcc\xfd\xa4\x8a\x75\x1c\x7d\x88\xd6\x32\x1e\x8e\x20\x23\xa0\x60\xfd\x67\xae\x70\x09\x28\x2b\x92\xb1\xf9\x97\x6f\x4e\x93\xd4\x53\xfa\xcb\xb8\x1a\x42\x19\x15\x8b\x77\x59\xab\xe1\xde\xdb\x47\x34\xb4\x8a\x73\xa6\xd6\x0f\x2c\x64\xbf";
	uint8_t		groestl_out1[] = "\x98\xe4\xdc\x02\x81\xfa\x2c\xdf\x48\xe6\x16\x47\x5a\x42\x0d\xae\x42\x5c\x99\x46\x76\x30\xb0\xc4\xed\xb3\xae\x6e\xaf\xeb\xa8\x17\x1d\x28\x43\xfe\xa9\x19\xbb\x16\x9f\xd3\xc7\x63\x69\xdb\x10\xfd\xc9\x90\xea\x83\x22\x8d\xae\x51\xe2\x10\x35\xb4\xc1\x22\xd7\x65";
	uint8_t	   xpec4_512[] = "\xa9\x08\x52\x54\x52\x9e\xa2\x88\xf1\x65\x2a\x08\x43\xa3\xd9\xeb\x74\x63\x17\x55\x49\xc9\x31\xd3\xc3\x2d\x43\x1b\x6c\x03\x00\x00\xe6\xb8\xeb\xfb\x6f\x2a\x39\x2e\xe4\x99\x3d\x9d\xd1\xd5\x83\x23\x24\x9e\xa5\x49\xf5\xfe\x21\xc5\xf4\xad\x2d\x28\x64\x38\x87\xdc";

	// last 80 byte test from the second examples
	uint8_t			kin2[] = "\x01\x00\xdc\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x2a\xb0\x32\x51\x87\xd4\xf2\x8b\x6e\x22\xf0\x86\x48\x45\xdd\xd5\x0a\xc4\xe6\xaa\x22\xa1\x70\x9f\xfb\x42\x75\xd9\x25\xf2\x66\x36\x30\x0e\xed\x54\xff\xff\x0f\x1e\xa4\x0d\x12\x00";
	uint8_t	 keccak_out2[] = "\x88\x23\x71\xa8\x39\x11\x1f\x35\x16\x48\xd3\x43\xec\x4d\x03\x57\x7f\x8a\xe7\x7e\x34\x00\x89\x19\x95\x31\xc6\xd0\x16\x46\x03\x39\x3d\xb7\xba\xd8\xfd\x86\x1e\x6b\x6b\x35\x29\x2d\xeb\x4e\x42\xa1\xd1\x22\x1e\x49\x3f\x17\xc1\x4a\x8b\x5d\x1c\x0a\x58\x4c\x5c\x16";
	uint8_t	groestl_out2[] = "\x97\xf4\x33\x0b\xe1\x2c\x28\x78\xa8\x27\xfd\xeb\xfb\x57\x48\x0a\xa9\x30\xd8\x82\xd5\x7f\x72\x50\xac\x53\x50\x8d\xf5\x0c\x97\xe6\xca\x81\xcb\xd4\x98\xd0\x68\x5a\xb8\x6d\x81\x1e\x8d\xa3\x83\x60\x39\x85\x8f\x8d\x5c\x01\x98\x3f\xb9\x9e\x02\x35\x4b\xe8\x5b\x3f";
	uint8_t		 jh_out2[] = "\x9a\x00\xcf\xb9\x80\xa8\x6e\xab\x6c\x2f\x24\x2c\x65\x4e\x15\x8b\xca\x86\x4b\x8d\x4c\x2f\x56\x0c\x44\x82\x3e\x09\x64\xcc\xdc\x0d\x24\xde\xe8\x49\x5f\x33\x76\xf4\x70\x24\xfa\x11\xef\x6d\x88\x56\x8b\x39\x4e\x42\x42\x9b\x93\x0c\x45\xad\x4c\x9f\x01\x2c\x83\x60";
	uint8_t	  blake_out2[] = "\x0a\x1b\x33\x3a\x0f\xfc\x3a\x3c\x3a\x59\xfc\x79\x2b\x1b\x99\x04\x6e\x57\xa6\x31\xa2\x6c\x52\xfc\xcb\x11\x46\x12\xc3\xfc\x79\x4a\x96\x67\xdd\xa8\x6a\x19\xfd\x20\x34\x3f\x22\x0e\xc5\xd1\x4b\x3f\x4b\x32\xf6\x76\xd8\xce\xf4\x10\x98\x54\x05\x30\xca\x3f\x19\x6f";
	uint8_t	  skein_out2[] = "\xa9\x08\x52\x54\x52\x9e\xa2\x88\xf1\x65\x2a\x08\x43\xa3\xd9\xeb\x74\x63\x17\x55\x49\xc9\x31\xd3\xc3\x2d\x43\x1b\x6c\x03\x00\x00\xe6\xb8\xeb\xfb\x6f\x2a\x39\x2e\xe4\x99\x3d\x9d\xd1\xd5\x83\x23\x24\x9e\xa5\x49\xf5\xfe\x21\xc5\xf4\xad\x2d\x28\x64\x38\x87\xdc";

	unsigned	passed = 0;
	unsigned	failed = 0;
	unsigned	i;

	// Replicate the order of hashes that occurs in ZR5 for a test4 input
	//
	// test_single_hash(input, len, expected, algoIndex, passedTestsPtr, failedTestsPtr)
	test_single_hash(kin1, 80, keccak_out1, KECCAK_ID, &passed, &failed);
	test_single_hash(keccak_out1, 64, skein_out1, SKEIN_ID, &passed, &failed);
	test_single_hash(skein_out1, 64, blake_out1, BLAKE_ID, &passed, &failed);
	test_single_hash(blake_out1, 64, jh_out1, JH_ID, &passed, &failed);
	test_single_hash(jh_out1, 64, groestl_out1, GROESTL_ID, &passed, &failed);
	//
	// start the second round of hashes with the input from kin1 modified with PoK
	test_single_hash(kin2, 80, keccak_out2, KECCAK_ID, &passed, &failed);
	test_single_hash(keccak_out2, 64, groestl_out2, GROESTL_ID, &passed, &failed);
	test_single_hash(groestl_out2, 64, jh_out2, JH_ID, &passed, &failed);
	test_single_hash(jh_out2, 64, blake_out2, BLAKE_ID, &passed, &failed);
	test_single_hash(blake_out2, 64, skein_out2, SKEIN_ID, &passed, &failed);

	*passedTestsPtr += passed;
	*failedTestsPtr += failed;

	return(passed);
}


short test_single_hash(uint8_t* input, unsigned len, uint8_t* expected, uint8_t algoIndex, unsigned * passedTestsPtr, unsigned * failedTestsPtr)
{
	uint8_t		output512[64];
	unsigned	i;
	char 		algorithms[][10] = {"Keccak", "Blake", "Groestl", "JH", "Skein" };
	char *		algoName = NULL;
	unsigned	passed = 0;
	unsigned	failed = 0;

	switch(algoIndex)	{
		case KECCAK_ID:
			sph_keccak512_context	ctx_keccak;		// context for a Keccak hash
			sph_keccak512_init(&ctx_keccak);
			sph_keccak512 (&ctx_keccak, input, len);
			sph_keccak512_close(&ctx_keccak, output512);
			break;
        case BLAKE_ID:
			sph_blake512_context	ctx_blake;		// context for a Blake hash
			sph_blake512_init(&ctx_blake);
            sph_blake512(&ctx_blake, input, len);
            sph_blake512_close(&ctx_blake, output512);
            break;
        case GROESTL_ID:
			sph_groestl512_context	ctx_groestl;	// context for a Groestl hash
			sph_groestl512_init(&ctx_groestl);
            sph_groestl512(&ctx_groestl, input, len);
            sph_groestl512_close(&ctx_groestl, output512);
            break;
        case JH_ID:
			sph_jh512_context		ctx_jh;			// context for a JH hash
			sph_jh512_init(&ctx_jh);
            sph_jh512(&ctx_jh, input, len);
            sph_jh512_close(&ctx_jh, output512);
            break;
        case SKEIN_ID:
			sph_skein512_context	ctx_skein;		// context for a Skein hash
			sph_skein512_init(&ctx_skein);
            sph_skein512(&ctx_skein, input, len);
            sph_skein512_close(&ctx_skein, output512);
			break;
		default:
			return(0);
	}
	if(memcmp((void *)expected, (void *)output512, 64) == 0)
		passed += 1;
	else {
		failed += 1;
		#ifdef TEST_VERBOSELY
		printf("%s output did not match.\n", algoName);
		printf("%12s", "From input:\n");
		for(i=0; i< len; i++) { printf("%02x", input[i]); }
		printf("\n");
		printf("%12s", "Expected:\n");
		for(i=0; i< 64; i++) { printf("%02x", expected[i]); }
		printf("\n");
		printf("%12s", "But got:\n");
		for(i=0; i< 64; i++) { printf("%02x", output512[i]); }
		printf("\n\n");
		#endif // TEST_VERBOSELY
	}
	*passedTestsPtr += passed;
	*failedTestsPtr += failed;

	return(passed);
}


short test_zr5_hash_512(unsigned * passedTestsPtr, unsigned * failedTestsPtr)
{
	uint8_t		zr5_out_512[64];	// results for testing zr5_hash_512
	uint8_t		passed = 0;
	uint8_t		failed = 0;
	unsigned	i;

	uint8_t		   test4[] = "\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x2a\xb0\x32\x51\x87\xd4\xf2\x8b\x6e\x22\xf0\x86\x48\x45\xdd\xd5\x0a\xc4\xe6\xaa\x22\xa1\x70\x9f\xfb\x42\x75\xd9\x25\xf2\x66\x36\x30\x0e\xed\x54\xff\xff\x0f\x1e\xa4\x0d\x12\x00";
	uint8_t		groestl4[] = "\x98\xe4\xdc\x02\x81\xfa\x2c\xdf\x48\xe6\x16\x47\x5a\x42\x0d\xae\x42\x5c\x99\x46\x76\x30\xb0\xc4\xed\xb3\xae\x6e\xaf\xeb\xa8\x17\x1d\x28\x43\xfe\xa9\x19\xbb\x16\x9f\xd3\xc7\x63\x69\xdb\x10\xfd\xc9\x90\xea\x83\x22\x8d\xae\x51\xe2\x10\x35\xb4\xc1\x22\xd7\x65";
	uint8_t	   xpec4_512[] = "\xa9\x08\x52\x54\x52\x9e\xa2\x88\xf1\x65\x2a\x08\x43\xa3\xd9\xeb\x74\x63\x17\x55\x49\xc9\x31\xd3\xc3\x2d\x43\x1b\x6c\x03\x00\x00\xe6\xb8\xeb\xfb\x6f\x2a\x39\x2e\xe4\x99\x3d\x9d\xd1\xd5\x83\x23\x24\x9e\xa5\x49\xf5\xfe\x21\xc5\xf4\xad\x2d\x28\x64\x38\x87\xdc";
	uint8_t		   test5[] = "\x01\x00\xdc\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x2a\xb0\x32\x51\x87\xd4\xf2\x8b\x6e\x22\xf0\x86\x48\x45\xdd\xd5\x0a\xc4\xe6\xaa\x22\xa1\x70\x9f\xfb\x42\x75\xd9\x25\xf2\x66\x36\x30\x0e\xed\x54\xff\xff\x0f\x1e\xa4\x0d\x12\x00";
	uint8_t		  skein5[] = "\xa9\x08\x52\x54\x52\x9e\xa2\x88\xf1\x65\x2a\x08\x43\xa3\xd9\xeb\x74\x63\x17\x55\x49\xc9\x31\xd3\xc3\x2d\x43\x1b\x6c\x03\x00\x00\xe6\xb8\xeb\xfb\x6f\x2a\x39\x2e\xe4\x99\x3d\x9d\xd1\xd5\x83\x23\x24\x9e\xa5\x49\xf5\xfe\x21\xc5\xf4\xad\x2d\x28\x64\x38\x87\xdc";

	// test 512 bit output for case 4
	zr5_hash_512(test4, zr5_out_512, 80 );
	if(memcmp((void *)groestl4, (void *)zr5_out_512, 64) == 0)
		passed += 1;
	else {
		failed += 1;
		#ifdef TEST_VERBOSELY
		printf("ZR5-512 output did not match.\n");
		printf("%12s", "Expected ZR5-512 output for test 4:\n");
		for(i=0; i< 64; i++) { printf("%02x", groestl4[i]); }
		printf("\n");
		printf("%12s", "Got:\n");
		for(i=0; i< 64; i++) { printf("%02x", zr5_out_512[i]); }
		printf("\n\n");
		#endif // TEST_VERBOSELY
	}

	// test 512 bit output for case 5
	zr5_hash_512(test5, zr5_out_512, 80 );
	if(memcmp((void *)skein5, (void *)zr5_out_512, 64) == 0)
		passed += 1;
	else {
		failed += 1;
		#ifdef TEST_VERBOSELY
		printf("ZR5-512 output did not match.\n");
		printf("%12s", "Expected ZR5-512 output for test 5:\n");
		for(i=0; i< 64; i++) { printf("%02x", skein5[i]); }
		printf("\n");
		printf("%12s", "Got:\n");
		for(i=0; i< 64; i++) { printf("%02x", zr5_out_512[i]); }
		printf("\n\n");
		#endif // TEST_VERBOSELY
	}
	*passedTestsPtr += passed;
	*failedTestsPtr += failed;

	return(passed);
}


short test_zr5(unsigned * passedTestsPtr, unsigned * failedTestsPtr)
{
	// another 80 byte test from the second examples
	uint8_t		   test4[] = "\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x2a\xb0\x32\x51\x87\xd4\xf2\x8b\x6e\x22\xf0\x86\x48\x45\xdd\xd5\x0a\xc4\xe6\xaa\x22\xa1\x70\x9f\xfb\x42\x75\xd9\x25\xf2\x66\x36\x30\x0e\xed\x54\xff\xff\x0f\x1e\xa4\x0d\x12\x00";
	uint8_t		   zr5_4[] = "\xa9\x08\x52\x54\x52\x9e\xa2\x88\xf1\x65\x2a\x08\x43\xa3\xd9\xeb\x74\x63\x17\x55\x49\xc9\x31\xd3\xc3\x2d\x43\x1b\x6c\x03\x00\x00";
	uint8_t		   test5[] = "\x01\x00\x00\x00\x3c\x49\xe7\xa2\x7e\xcb\x9f\x44\x0e\xee\x82\xdc\x92\xe3\x05\x8c\x1d\x9b\xc1\xb0\xd7\x44\x08\xa2\xcd\x33\x40\xea\x25\x00\x00\x00\x7a\x97\x38\xf0\x2a\xc4\xeb\xbb\xa1\xcf\x65\xe4\x5a\x6b\xfa\x43\x7a\x26\x83\x70\x72\x56\x23\xce\x44\xbe\xff\x40\x0c\xe1\x0e\xee\xcf\xb9\xf2\x54\xff\xff\x5f\x1d\x2e\xdb\x03\x00";
	unsigned	test5_len  = 80;
	uint8_t		   zr5_5[] = "\x00\x00\x00\x0a\x13\x4b\xda\x5f\xfa\x72\x82\xb5\xe7\xe3\x8d\xcf\xe2\x15\x77\x69\xe4\xd2\xec\x32\xe1\xd4\x41\x45\x6e\xe9\x2d\x5d";
	uint8_t		   test6[] = "\x01\x00\x00\x00\x66\x7e\xca\x14\x23\x74\x62\xbd\xe5\xa1\x8a\xce\x2b\xa8\xa9\x72\x2e\x20\x45\x6e\x54\xa1\x44\x4a\x42\x49\x6e\x81\x46\x00\x00\x00\x7c\xc0\xd2\x1f\xc8\xa0\x60\xd7\x3b\xe6\x59\x8c\xb7\xd9\x90\xff\x2b\xce\xf1\xf7\xa7\xad\xe4\xad\xde\xe2\x59\xc3\x61\x67\xda\x93\x25\xba\xf2\x54\xff\xff\x5f\x1d\x95\x81\x05\x00";
	unsigned	test6_len  = 80;
	uint8_t		   zr5_6[] = "\x00\x00\x00\x53\x40\xd6\x94\x4e\x66\xd5\x58\x5b\x47\x1b\xf4\x80\xf8\x9d\x23\x3a\xbc\x8f\x40\xff\x9b\x34\x2f\xee\x0e\xb9\x3e\x04";


	uint8_t		zr5_out_256[32];	// results for testing zr5_hash_512
	uint8_t		passed = 0;
	uint8_t		failed = 0;
	unsigned	i;

	// test 256 bit output for case 4
	zr5_hash(test4, zr5_out_256, 80 );
	if(memcmp((void *)zr5_4, (void *)zr5_out_256, 32) == 0)
		passed += 1;
	else {
		failed += 1;
		#ifdef TEST_VERBOSELY
		printf("ZR5-256 output did not match.\n");
		printf("%12s", "Expected ZR5-256 output for test 4:\n");
		for(i=0; i< 32; i++) { printf("%02x", zr5_4[i]); }
		printf("\n");
		printf("%12s", "Got:\n");
		for(i=0; i< 32; i++) { printf("%02x", zr5_out_256[i]); }
		printf("\n\n");
		#endif // TEST_VERBOSELY
	}

	// test 256 bit output for case 5
	zr5_hash(test5, zr5_out_256, test5_len );
	if(memcmp((void *)zr5_5, (void *)zr5_out_256, 32) == 0)
		passed += 1;
	else {
		failed += 1;
		#ifdef TEST_VERBOSELY
		printf("ZR5-256 output did not match.\n");
		printf("%12s", "Expected ZR5-256 output for test 4:\n");
		for(i=0; i< 32; i++) { printf("%02x", zr5_5[i]); }
		printf("\n");
		printf("%12s", "Got:\n");
		for(i=0; i< 32; i++) { printf("%02x", zr5_out_256[i]); }
		printf("\n\n");
		#endif // TEST_VERBOSELY
	}

	// test 256 bit output for case 6
	zr5_hash(test6, zr5_out_256, test6_len );
	if(memcmp((void *)zr5_6, (void *)zr5_out_256, 32) == 0)
		passed += 1;
	else {
		failed += 1;
		#ifdef TEST_VERBOSELY
		printf("ZR5-256 output did not match.\n");
		printf("%12s", "Expected ZR5-256 output for test 4:\n");
		for(i=0; i< 32; i++) { printf("%02x", zr5_6[i]); }
		printf("\n");
		printf("%12s", "Got:\n");
		for(i=0; i< 32; i++) { printf("%02x", zr5_out_256[i]); }
		printf("\n\n");
		#endif // TEST_VERBOSELY
	}

	*passedTestsPtr += passed;
	*failedTestsPtr += failed;
	return(passed);
}
